package com.basic.business.prodRel.service.impl;

import cn.idev.excel.EasyExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.enums.CellExtraTypeEnum;
import cn.idev.excel.metadata.CellExtra;
import cn.idev.excel.read.listener.ReadListener;
import cn.idev.excel.write.style.HorizontalCellStyleStrategy;
import com.basic.business.img.domain.TImagesInfo;
import com.basic.business.img.mapper.TImagesInfoMapper;
import com.basic.business.mat.domain.TMatMgmt;
import com.basic.business.mat.mapper.TMatMgmtMapper;
import com.basic.business.prodRel.domain.TProdRelDetails;
import com.basic.business.prodRel.domain.excel.TProdRelExportExcel;
import com.basic.business.prodRel.domain.excel.TProdRelTmplExcel;
import com.basic.business.prodRel.mapper.TProdRelDetailsMapper;
import com.basic.business.store.domain.TStoreMgmt;
import com.basic.business.store.mapper.TStoreMgmtMapper;
import com.basic.common.annotation.FileExport;
import com.basic.common.config.BasicConfig;
import com.basic.common.constant.CacheConstants;
import com.basic.common.core.domain.AjaxResult;
import com.basic.common.core.redis.RedisCacheUtils;
import com.basic.common.utils.StringUtils;
import com.basic.common.utils.bean.BeanUtils;
import com.basic.common.utils.easyExcel.DropDownWriteHandler;
import com.basic.common.utils.easyExcel.EasyExcelUtils;
import com.basic.common.utils.easyExcel.ExcelServeMergeStrategy;
import com.basic.common.utils.easyExcel.StyleUtils;
import com.basic.common.utils.file.FileUploadUtils;
import org.springframework.stereotype.Service;
import com.basic.common.core.service.impl.BaseServiceImpl;
import com.basic.business.prodRel.domain.TProdRelMain;
import com.basic.business.prodRel.service.ITProdRelMainService;
import com.basic.business.prodRel.mapper.TProdRelMainMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品关系Service业务层处理
 *
 * @author zhaoxy_jn@163.com
 */
@Service
public class TProdRelMainServiceImpl extends BaseServiceImpl<TProdRelMainMapper,TProdRelMain> implements ITProdRelMainService {

    @Resource
    private TProdRelMainMapper tProdRelMainMapper;

    @Resource
    private TProdRelDetailsMapper tProdRelDetailsMapper;

    @Resource
    private TMatMgmtMapper tMatMgmtMapper;

    @Resource
    private TStoreMgmtMapper tStoreMgmtMapper;

    @Resource
    private TImagesInfoMapper tImagesInfoMapper;

    @Resource
    private ITProdRelMainService prodRelMainService;

    /**
     * 项目启动时，初始化印刷品编码缓存
     */
    @PostConstruct
    public void init(){
        resetProdRelCache();
    }


    @Transactional
    @Override
    public String insertProdRelMain(TProdRelMain po) {
        super.insert(po);
        po.getProdRelDetailsList().forEach(item-> item.setMainId(po.getId()));
        tProdRelDetailsMapper.batchInsert(po.getProdRelDetailsList());
        return po.getId();
    }

    @Transactional
    @Override
    public int update(TProdRelMain po){
        // 清空明细
        tProdRelDetailsMapper.delDetailsByMainId(po.getId());
        po.getProdRelDetailsList().forEach(item-> item.setMainId(po.getId()));
        tProdRelDetailsMapper.batchInsert(po.getProdRelDetailsList());
        return super.update(po);
    }

    @Transactional
    @Override
    public int deleteByIds(Object[] ids){
        // 删除明细
        tProdRelDetailsMapper.delDetailsByMainIds(ids);
        return super.deleteByIds(ids);
    }


    @Override
    public int updateStatusByIds(String[] ids, String status) {
        return tProdRelMainMapper.updateStatusByIds(ids, status);
    }

    @Override
    public void exportTemplate(HttpServletResponse response) {
        try {
            // 获取是否印刷品下拉框
            List<String> isPrintList = Arrays.asList("是","否");
            // 获取店铺简称列表
            List<String> shopNameList = tStoreMgmtMapper.getNormalStoreMgmtList().stream().map(TStoreMgmt::getStoreAbbr).collect(Collectors.toList());
            // 获取材质下拉框
            List<String> materialList = tMatMgmtMapper.getNormalMatMgmtList().stream().map(TMatMgmt::getMatName).collect(Collectors.toList());

            EasyExcel.write(response.getOutputStream(), TProdRelTmplExcel.class).sheet("商品关系模板")
                    // 加载店铺简称
                    .registerWriteHandler(new DropDownWriteHandler(shopNameList, 0))
                    // 加载印刷品
                    .registerWriteHandler(new DropDownWriteHandler(isPrintList, 3))
                    // 加载材质
                    .registerWriteHandler(new DropDownWriteHandler(materialList, 7))
                    .doWrite(Collections.emptyList());
        }catch (Exception e) {
            throw new RuntimeException("生成商品关系模板失败");
        }
    }

    @Transactional
    @Override
    public AjaxResult importTemplate(MultipartFile file, boolean coverSupport) {
        // 存储错误信息
        List<String> errorMessages = new ArrayList<>();
        try {

            List<TProdRelTmplExcel> dataList = new ArrayList<>();

            List<CellExtra> extraList = new ArrayList<>();

            EasyExcel.read(file.getInputStream(), TProdRelTmplExcel.class, new ReadListener<TProdRelTmplExcel>() {

                @Override
                public void invoke(TProdRelTmplExcel tProdRelTmplExcel, AnalysisContext analysisContext) {
                    dataList.add(tProdRelTmplExcel);
                }

                @Override
                public void extra(CellExtra extra, AnalysisContext context) {
                    CellExtraTypeEnum type = extra.getType();
                    if (type == CellExtraTypeEnum.MERGE) {
                        extraList.add(extra);
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) { }
            }).extraRead(CellExtraTypeEnum.MERGE).sheet().headRowNumber(2).doRead();


            // 解析完之后，对数据进行合并
            List<TProdRelTmplExcel> list = EasyExcelUtils.explainMergeData(dataList, extraList, 2);

            if (list.isEmpty()) {
                return AjaxResult.error("导入文件为空");
            }
            // 获取所有的店铺的主键和简称,转换成map，key是shopAbbr，value是id
            Map<String, String> storeMap = tStoreMgmtMapper.getNormalStoreMgmtList().stream().collect(Collectors.toMap(TStoreMgmt::getStoreAbbr, TStoreMgmt::getId));
            // 获取所有材质的主键和名称,转换成map，key是matName，value是id
            Map<String, String> materialMap = tMatMgmtMapper.getNormalMatMgmtList().stream().collect(Collectors.toMap(TMatMgmt::getMatName, TMatMgmt::getId));

            // 分组数据
            Map<String, List<TProdRelTmplExcel>> groupedData = list.stream().collect(Collectors.groupingBy(TProdRelTmplExcel::getMark));

            // 获取商品id
            List<String> productIds = tProdRelMainMapper.getProductIds();


            // 先校验店铺和材质是否存在
            for (TProdRelTmplExcel item : list) {
                int rowIndex = list.indexOf(item) + 3;
                // 校验店铺是否存在
                String shopId = storeMap.get(item.getShopName());
                if (shopId == null) {
                    errorMessages.add(String.format("第%d行，店铺名称不存在", rowIndex));
                }
                String imgMaterial = item.getImgMaterial();
                String materialId = materialMap.get(imgMaterial);
                if (materialId == null) {
                    errorMessages.add(String.format("第%d行，材质名称不存在", rowIndex));
                }

                if (coverSupport) {
                    // 校验商品ID是否已存在
                    String productId = item.getProductId();
                    // 判断productId是否在productIds集合中
                    if (productIds.contains(productId)) {
                        errorMessages.add(String.format("第%d行，商品ID已存在", rowIndex));
                    }
                }

            }

            // 如果有错误，直接返回
            if (!errorMessages.isEmpty()) {
                return AjaxResult.error(errorMessages.toString());
            }

            // 批量入库
            for (Map.Entry<String, List<TProdRelTmplExcel>> entry : groupedData.entrySet()) {
                List<TProdRelTmplExcel> group = entry.getValue();
                if (!group.isEmpty()) {
                    TProdRelTmplExcel firstItem = group.get(0);

                    TProdRelMain po = new TProdRelMain();
                    po.setId(firstItem.getMark());
                    po.setShopId(storeMap.get(firstItem.getShopName()));
                    po.setShopName(firstItem.getShopName());
                    po.setLink(firstItem.getLink());
                    po.setProductId(firstItem.getProductId());
                    po.setPrintedMaterials(StringUtils.equals(firstItem.getPrintedMaterials(), "是") ? "Y" : "N");

                    tProdRelMainMapper.insert(po);

                    // 插入子表数据
                    List<TProdRelDetails> detailsList = group.stream()
                            .map(item -> {
                                TProdRelDetails detail = new TProdRelDetails();
                                detail.setMainId(po.getId());
                                detail.setImgId(item.getImgId());
                                detail.setImgNum(item.getImgNum());
                                detail.setImgDimensions(item.getImgDimensions());
                                detail.setImgMaterial(materialMap.get(item.getImgMaterial()));
                                return detail;
                            })
                            .collect(Collectors.toList());
                    tProdRelDetailsMapper.batchInsert(detailsList);
                }
            }

            prodRelMainService.export(dataList);

        }catch (Exception e) {
            return AjaxResult.error(String.format("导入失败：%s", e));
        }
        return AjaxResult.success();
    }

    @Override
    public void resetProdRelCache() {
        // 清空缓存
        RedisCacheUtils.clearCache(CacheConstants.PROD_REL_REDIS_KEY + "*");
        // 加载缓存
        loadingProdRelCache();
    }

    /**
     * 加载商品关系缓存
     */
    private void loadingProdRelCache() {
        Map<String, List<TProdRelDetails>> prodRelMap = tProdRelDetailsMapper.getNormalProdRel().stream().collect(Collectors.groupingBy(TProdRelDetails::getMainId));
        for (Map.Entry<String, List<TProdRelDetails>> entry : prodRelMap.entrySet()) {
            RedisCacheUtils.setCacheObject(CacheConstants.PROD_REL_REDIS_KEY + entry.getKey(), entry.getValue());
        }
    }


    /**
     * 商品关系导出
     */
    @FileExport(fileName = "商品关系导出.xlsx")
    @Override
    public String export(List<TProdRelTmplExcel> list) throws IOException {
        String realFileName = EasyExcelUtils.extractFilename();
        String fileUrl = FileUploadUtils.getPathFileName(BasicConfig.getDownloadCenterPath(), realFileName);
        try {

            // 拷贝对象
            List<TProdRelExportExcel> exportList = new ArrayList<>();
            for (TProdRelTmplExcel tProdRelTmplExcel : list) {
                TProdRelExportExcel tProdRelExportExcel = new TProdRelExportExcel();
                // 获取图片信息
                TImagesInfo tImagesInfo = tImagesInfoMapper.get(tProdRelTmplExcel.getImgId());
                if (tImagesInfo != null) {
                    tProdRelExportExcel.setImgPngPath(tImagesInfo.getBucketUrl() + tImagesInfo.getImgPngPath());
                    tProdRelExportExcel.setImgName(tImagesInfo.getImgName());
                }

                BeanUtils.copyProperties(tProdRelTmplExcel, tProdRelExportExcel);
                exportList.add(tProdRelExportExcel);
            }

            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle());
            EasyExcel.write(FileUploadUtils.getAbsoluteFile(BasicConfig.getDownloadCenterPath(), realFileName), TProdRelExportExcel.class)
                    .registerWriteHandler(new ExcelServeMergeStrategy(TProdRelExportExcel.class, 2))
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .sheet("商品关系数据").doWrite(exportList);
        } catch (Exception e) {
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
        return fileUrl;
    }

}
